package com.baturu.vin.honda.service.impl;

import com.baturu.carvin.dtos.CarTypeDTO;
import com.baturu.carvin.service.CarTypeService;
import com.baturu.carvin.service.impl.AppConfigLoader;
import com.baturu.kit.kit.guava2.Lists2;
import com.baturu.kit.kit.guava2.Sets2;
import com.baturu.vin.base.service.impl.SuperEPCAnalyser;
import com.baturu.vin.dto.EPCImagePointDTO;
import com.baturu.vin.dto.EPCPartsImageDTO;
import com.baturu.vin.dto.EPCPartsImagePositionDTO;
import com.baturu.vin.dto.superEPC.*;
import com.baturu.vin.dto.superEPC.entity.SEPCCarTypeQueryParam;
import com.baturu.vin.dto.superEPC.entity.SEPCGroupQueryParam;
import com.baturu.vin.dto.superEPC.entity.SEPCPartsQueryParam;
import com.baturu.vin.enums.LangEnum;
import com.baturu.vin.honda.dal.dao.*;
import com.baturu.vin.honda.dto.*;
import com.baturu.vin.honda.transformer.SEPCCarTypeTransformer;
import com.baturu.vin.honda.transformer.SEPCGroupTransformer;
import com.baturu.vin.honda.transformer.SEPCPartsTransformer;
import com.baturu.vin.kit.StreamKit;
import com.baturu.vin.kit.VinValidator;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: chenjiahao
 * @Time: 2019/5/7
 */
@Service("hondaSuperEPCAnalyser")
@Slf4j
public class HondaSuperEPCAnalyser extends SuperEPCAnalyser {

    @Autowired
    private HondaPartsMappingDAO partsMappingDAO;

    @Autowired
    private HondaVinDAO hondaVinDAO;

    @Autowired
    private SEPCHondaGroupDAO hondaGroupDAO;

    @Autowired
    private AppConfigLoader appConfigLoader;

    @Autowired
    private SEPCHondaPartsDAO sepcHondaPartsDAO;

    @Autowired
    private HondaPartDAO hondaPartDAO;

    protected final int SEGMENT_QUERY_SIZE = 150;

    @Autowired
    private HondaEPCAnalyser hondaEPCAnalyser;

    @Autowired
    private CarTypeService carTypeService;


    @Override
    public List<SEPCCarTypeDTO> querySuperEPCCarTypeByVinCode(SEPCCarTypeQueryParam param) {
        String vinCode = param.getVinCode();
        if (vinCode.startsWith("L") && !VinValidator.fullValidate(vinCode)) {
            log.info("被美规车过滤");
            return Collections.emptyList();
        }
        List<SEPCCarTypeDTO> threeCarType = findThreeCarType(param.getSuperCarTypeDTO());
        if (CollectionUtils.isNotEmpty(threeCarType)) {
            return threeCarType;
        }

        List<SEPCCarTypeDTO> secondCarType = findSecondCarType(param.getSuperCarTypeDTO());
        if (CollectionUtils.isNotEmpty(secondCarType)) {
            return secondCarType;
        }
        String vinSub9 = vinCode.substring(9);
        List<HondaVinInfoDTO> vinInfos = hondaVinDAO.getVinInfo(vinCode.substring(0, 11), vinSub9);
        if (CollectionUtils.isEmpty(vinInfos)) {
            String vinPre11 = vinCode.substring(0, 8) + "*" + vinCode.substring(9, 11);
            vinInfos = hondaVinDAO.getVinInfo(vinPre11, vinSub9);
        }
        if (CollectionUtils.isEmpty(vinInfos)) {
            return Collections.emptyList();
        }

        Map<String, List<HondaVinInfoDTO>> disk2VinInfo = vinInfos.stream().collect(Collectors.groupingBy(HondaVinInfoDTO::getDisk));
//        String maxDisk = disk2VinInfo.keySet().stream().max(Comparator.comparing(String::toString)).orElse("");
//        String maxDisk = hondaVinInfoDTO.getDisk();
        String maxDisk = vinInfos.stream()
                .max(Comparator.comparingInt(d -> Integer.parseInt(d.getDisk())))
                .map(HondaVinInfoDTO::getDisk).get();
        vinInfos = disk2VinInfo.getOrDefault(maxDisk, Lists.newArrayList());
        vinInfos.forEach(d -> d.setVinCode(vinCode));
        if (vinInfos.size() > 1) {
            return dealMultiCarType(vinInfos);

        }
        setCMNOPTAndCarSystem(vinInfos);
        return Lists2.transformNonNull(vinInfos, SEPCCarTypeTransformer.VIN_INFO_TO_SEPC_CAR_TYPE);
    }

    private List<SEPCCarTypeDTO> dealMultiCarType(List<HondaVinInfoDTO> vinInfos) {
        Set<SEPCCarTypeDTO> carType = Sets2.transformNonNull(vinInfos, SEPCCarTypeTransformer.VIN_INFO_TO_MULTI_SEPC_CAR_TYPE);
        if (carType.size() > 1) {
            return Lists.newArrayList(carType);
        }
        return getRemarkCarType(vinInfos);
    }

    private List<SEPCCarTypeDTO> getRemarkCarType(List<HondaVinInfoDTO> vinInfos) {
        setCMNOPTAndCarSystem(vinInfos);
        return Lists2.transformNonNull(vinInfos, SEPCCarTypeTransformer.VIN_INFO_TO_MULTI_HMODTYP_SEPC_CAR_TYPE);
    }

    private List<SEPCCarTypeDTO> findThreeCarType(SEPCCarTypeDTO superCarTypeDTO) {
        if (Objects.isNull(superCarTypeDTO) || CollectionUtils.isEmpty(superCarTypeDTO.getExtendAttrDTOs())) {
            return Collections.emptyList();
        }
        Optional<String> hmodtyp = superCarTypeDTO.getExtendAttrDTOs().stream()
                .filter(d -> "hmodtyp".equals(d.getCode()))
                .map(d -> d.getValue().toString())
                .findFirst();
        Optional<String> disk = superCarTypeDTO.getExtendAttrDTOs().stream()
                .filter(d -> "disk".equals(d.getCode()))
                .map(d -> d.getValue().toString())
                .findFirst();
        if (!hmodtyp.isPresent() || !disk.isPresent()) {
            return Collections.emptyList();
        }
        String vinCode = superCarTypeDTO.getVinCode();
        String vinSub9 = vinCode.substring(9);
        List<HondaVinInfoDTO> vinInfos = hondaVinDAO.getVinInfoByHmodtyp(vinCode.substring(0, 11), vinSub9, hmodtyp.get(), disk.get());
        if (CollectionUtils.isEmpty(vinInfos)) {
            String vinPre11 = vinCode.substring(0, 8) + "*" + vinCode.substring(9, 11);
            vinInfos = hondaVinDAO.getVinInfoByHmodtyp(vinPre11, vinSub9, hmodtyp.get(), disk.get());
        }
        vinInfos.forEach(d -> d.setVinCode(vinCode));
        if (vinInfos.size() != 1) {
            log.warn("本田第二层车型没有锁准,请排查");
            return Collections.emptyList();
        }
        setCMNOPTAndCarSystem(vinInfos);
        return Lists2.transformNonNull(vinInfos, SEPCCarTypeTransformer.VIN_INFO_TO_SEPC_CAR_TYPE);
    }

    private List<SEPCCarTypeDTO> findSecondCarType(SEPCCarTypeDTO superCarTypeDTO) {
        if (Objects.isNull(superCarTypeDTO) || CollectionUtils.isEmpty(superCarTypeDTO.getCarTypeDetailDTOList()) || CollectionUtils.isEmpty(superCarTypeDTO.getExtendAttrDTOs())) {
            return Collections.emptyList();
        }
        String vinCode = superCarTypeDTO.getVinCode();
        List<SEPCCarTypeDetailDTO> carTypeDetailDTOList = superCarTypeDTO.getCarTypeDetailDTOList();
        Optional<SEPCCarTypeDetailDTO> oneLabel = carTypeDetailDTOList.stream().filter(d -> "multiCarType".equals(d.getCode())).findFirst();
        if (!oneLabel.isPresent() || CollectionUtils.isEmpty(oneLabel.get().getSubValue())) {
            return Collections.emptyList();
        }
        List<SEPCCarTypeDetailDTO> subValue = oneLabel.get().getSubValue();
        Optional<String> ctrsmtyp = subValue.stream().filter(d -> "ctrsmtyp".equals(d.getCode())).map(d -> d.getValue().toString()).findFirst();
        Optional<String> xgrade = subValue.stream().filter(d -> "xgradefulnam".equals(d.getCode())).map(d -> d.getValue().toString()).findFirst();
        Optional<String> carea = subValue.stream().filter(d -> "carea".equals(d.getCode())).map(d -> d.getValue().toString()).findFirst();
        Optional<String> disk = superCarTypeDTO.getExtendAttrDTOs().stream().filter(d -> "disk".equals(d.getCode())).map(d -> d.getValue().toString()).findFirst();
        if (!ctrsmtyp.isPresent() || !xgrade.isPresent() || !disk.isPresent() || !carea.isPresent()) {
            return Collections.emptyList();
        }
        String vinSub9 = vinCode.substring(9);
        List<HondaVinInfoDTO> vinInfos = hondaVinDAO.getVinInfoByMulti(vinCode.substring(0, 11), vinSub9, xgrade.get(), ctrsmtyp.get(), carea.get(), disk.get());
        if (CollectionUtils.isEmpty(vinInfos)) {
            String vinPre11 = vinCode.substring(0, 8) + "*" + vinCode.substring(9, 11);
            vinInfos = hondaVinDAO.getVinInfoByMulti(vinPre11, vinSub9, xgrade.get(), ctrsmtyp.get(), carea.get(), disk.get());
        }
        vinInfos.forEach(d -> d.setVinCode(vinCode));
        setCMNOPTAndCarSystem(vinInfos);
        if (vinInfos.size() <= 1) {
            return Lists2.transformNonNull(vinInfos, SEPCCarTypeTransformer.VIN_INFO_TO_SEPC_CAR_TYPE);
        }

        return Lists2.transformNonNull(vinInfos, SEPCCarTypeTransformer.VIN_INFO_TO_MULTI_HMODTYP_SEPC_CAR_TYPE);
    }

    private void setCMNOPTAndCarSystem(List<HondaVinInfoDTO> vinInfos) {
        if (CollectionUtils.isEmpty(vinInfos)) {
            return;
        }
        Set<Integer> hmodyp = vinInfos.stream().map(HondaVinInfoDTO::getHmodtyp).collect(Collectors.toSet());
//        Optional<String> maxDisk = vinInfos.stream().max(Comparator.comparing(HondaVinInfoDTO::getDisk)).map(HondaVinInfoDTO::getDisk);
        Optional<String> maxDisk = vinInfos.stream().max(Comparator.comparingInt(d->Integer.parseInt(d.getDisk()))).map(HondaVinInfoDTO::getDisk);
        if (CollectionUtils.isEmpty(hmodyp) || !maxDisk.isPresent()) {
            return;
        }
        List<SEPCHondaMultiCarTypeDTO> list = hondaVinDAO.queryCMNOPT(hmodyp, maxDisk.get());
        Set<String> cmnopt = Sets2.transformNonNull(list, SEPCHondaMultiCarTypeDTO::getCmnopt);

        if (CollectionUtils.isNotEmpty(cmnopt)) {
            List<SEPCHondaMultiCarTypeDTO> cmnoptCh = hondaVinDAO.queryCMNOPTCh(cmnopt);
            Map<String, String> cmnopt2ch = cmnoptCh.stream().collect(Collectors.toMap(SEPCHondaMultiCarTypeDTO::getCmnopt, SEPCHondaMultiCarTypeDTO::getCh, (v1, v2) -> v1));
            Map<Integer, List<String>> hmodtyp2Cmnopt = list.stream().sorted(Comparator.comparing(SEPCHondaMultiCarTypeDTO::getCmnopt))
                    .collect(Collectors.groupingBy(SEPCHondaMultiCarTypeDTO::getHmodtyp,
                            Collectors.mapping(d -> cmnopt2ch.getOrDefault(d.getCmnopt(), d.getCmnopt()), Collectors.toList())));
            vinInfos.forEach(d -> d.setRemark(hmodtyp2Cmnopt.getOrDefault(d.getHmodtyp(), Lists.newArrayList())));
        }

        if (vinInfos.size() != 1) {
            return;
        }
        String btrId = vinInfos.get(0).getBtrId();
        List<CarTypeDTO> carTypeByBtrIds = carTypeService.findCarTypeByBtrIds(Lists.newArrayList(btrId));
        String carsystem = CollectionUtils.isNotEmpty(carTypeByBtrIds) ? carTypeByBtrIds.get(0).getCarSystem() : vinInfos.get(0).getCmodnamepc();
        vinInfos.get(0).setCarSystem(carsystem);
    }

    @Override
    public List<SEPCGroupDTO> queryGroupByVinCodeAndParentGroup(SEPCGroupQueryParam param) {
        SEPCGroupDTO groupDTO = param.getGroupDTO();
        if (Objects.isNull(groupDTO)) {
            if (LangEnum.ZH.getLang().equals(param.getLang())) {
                return hondaGroupDAO.queryMainGroupForCN();
            }
            return hondaGroupDAO.queryMainGroup();
        }
        SEPCCarTypeDTO superCarTypeDTO = param.getSuperCarTypeDTO();
        if (Objects.isNull(superCarTypeDTO) || CollectionUtils.isEmpty(superCarTypeDTO.getExtendAttrDTOs())) {
            return Collections.emptyList();
        }
        List<SEPCExtendAttributeDTO> extendAttrDTOs = superCarTypeDTO.getExtendAttrDTOs();
        //获取vin的所有子组
        Set<String> subGroupCode = getSubGroupCodeForVin(extendAttrDTOs);
        //获取子组
        List<SEPCHondaSubGroupDTO> subGroupCodeByMG = getSubGroupCodeByMG(extendAttrDTOs, subGroupCode, groupDTO);
        return Lists2.transformNonNull(subGroupCodeByMG, SEPCGroupTransformer.SUB_GROUP_TO_SEPC_SUB_GROUP);
    }

    private List<SEPCHondaSubGroupDTO> getSubGroupCodeByMG(List<SEPCExtendAttributeDTO> extendAttrDTOs, Set<String> subGroupCodeForVin, SEPCGroupDTO parentGroup) {
        if (CollectionUtils.isEmpty(extendAttrDTOs)) {
            return Collections.emptyList();
        }
        String mainGroupCode = parentGroup.getMainGroupCode();
        Optional<String> disk = extendAttrDTOs.stream()
                .filter(d -> "disk".equals(d.getCode()))
                .map(d -> d.getValue().toString())
                .findFirst();
        Optional<String> npl = extendAttrDTOs.stream()
                .filter(d -> "npl".equals(d.getCode()))
                .map(d -> d.getValue().toString())
                .findFirst();
        if (StringUtils.isEmpty(mainGroupCode) || !disk.isPresent() || !npl.isPresent()) {
            return Collections.emptyList();
        }
        List<SEPCHondaSubGroupDTO> subGroupCodeList = hondaGroupDAO.querySubCode(mainGroupCode, npl.get(), disk.get());
        subGroupCodeList.removeIf(d -> !subGroupCodeForVin.contains(d.getNplblk()));
        if (CollectionUtils.isEmpty(subGroupCodeList)) {
            return Collections.emptyList();
        }
        Set<String> subCode = subGroupCodeList.stream().map(SEPCHondaSubGroupDTO::getNplblk).collect(Collectors.toSet());
        List<SEPCHondaSubGroupDTO> subGroupDesList = hondaGroupDAO.querySubDes(npl.get(), subCode, disk.get());
        if (CollectionUtils.isEmpty(subGroupDesList)) {
            return subGroupCodeList;
        }
        List<SEPCHondaImageDTO> sepcHondaImageDTOS = hondaGroupDAO.queryImageByGroup(npl.get(), subCode, disk.get());
        if (CollectionUtils.isEmpty(sepcHondaImageDTOS)) {
            return subGroupCodeList;
        }
        //将des和imageCode set 进 subGroupCodeList
        setGroupDes(subGroupCodeList, subGroupDesList);
        setImageInGroupCode(subGroupCodeList, sepcHondaImageDTOS, npl.get(), disk.get());
        subGroupCodeList.forEach(d -> d.setMainGroup(parentGroup.getMainGroup()));
        return subGroupCodeList;
    }

    private void setImageInGroupCode(List<SEPCHondaSubGroupDTO> subGroupCodeList,
                                     List<SEPCHondaImageDTO> sepcHondaImageDTOS,
                                     String npl,
                                     String disk) {
        Map<String, List<SEPCHondaImageDTO>> nplblk2ImageList = sepcHondaImageDTOS.stream()
                .collect(Collectors.groupingBy(SEPCHondaImageDTO::getIllustrationNumber));
        subGroupCodeList.forEach(d -> {
            String imgPath = SEPCPartsTransformer.getImageURL(disk, npl, d.getNplblk());
            d.setImageUrl(imgPath);
            List<EPCPartsImageDTO> partsImageDTOs = buildEPCImage(nplblk2ImageList.get(d.getNplblk()), disk);
            d.setEpcPartsImageDTOList(partsImageDTOs);
        });
    }

    private List<EPCPartsImageDTO> buildEPCImage(List<SEPCHondaImageDTO> sepcHondaImageDTOS, String disk) {
        if (CollectionUtils.isEmpty(sepcHondaImageDTOS)) {
            return Collections.emptyList();
        }
        Map<String, List<SEPCHondaImageDTO>> imageCode2ImageDTO = sepcHondaImageDTOS.stream().collect(Collectors.groupingBy(SEPCHondaImageDTO::getIllustrationNumber));
        return imageCode2ImageDTO.values().stream().map(d -> converEPCImage(d, disk)).filter(Objects::nonNull).collect(Collectors.toList());
    }

    private EPCPartsImageDTO converEPCImage(List<SEPCHondaImageDTO> l, String disk) {
        if (CollectionUtils.isEmpty(l)) {
            return null;
        }
        SEPCHondaImageDTO input = l.get(0);
        EPCPartsImageDTO imageDTO = new EPCPartsImageDTO();
//        imageDTO.setImageUrl("honda/" + input.getNpl() + "/IMGE/" + input.getIllustrationNumber());
        imageDTO.setImageUrl(SEPCPartsTransformer.getImageURL(disk, input.getNpl(), input.getIllustrationNumber()));
        imageDTO.setImageName(input.getIllustrationNumber());
        imageDTO.setImageCode(input.getIllustrationNumber());
        List<EPCPartsImagePositionDTO> imagePositionDTOS = Lists.newArrayList();
        l.forEach(d -> {
            EPCImagePointDTO maxPoint = new EPCImagePointDTO();
            maxPoint.setX(d.getMinX());
            maxPoint.setY(d.getMinY());
            EPCImagePointDTO minPoint = new EPCImagePointDTO();
            minPoint.setX(d.getMaxX());
            minPoint.setY(d.getMaxY());

            EPCPartsImagePositionDTO positionDTO = new EPCPartsImagePositionDTO();
            positionDTO.setTopLeft(maxPoint);
            positionDTO.setBottomRight(minPoint);
            positionDTO.setPosition(d.getPartReferenceNumber());
            imagePositionDTOS.add(positionDTO);
        });
        imageDTO.setEpcPartsImagePositionDTOs(imagePositionDTOS);
        return imageDTO;
    }

    private void setGroupDes(List<SEPCHondaSubGroupDTO> subGroupCodeList, List<SEPCHondaSubGroupDTO> subGroupDesList) {
        Map<String, String> code2Des = subGroupDesList.stream()
                .collect(Collectors.toMap(SEPCHondaSubGroupDTO::getNplblk, SEPCHondaSubGroupDTO::getXplblk, (v1, v2) -> v1));
        subGroupCodeList.forEach(d -> d.setXplblk(code2Des.get(d.getNplblk())));
    }

    private Set<String> getSubGroupCodeForVin(List<SEPCExtendAttributeDTO> extendAttrDTOs) {
        Optional<String> disk = extendAttrDTOs.stream()
                .filter(d -> "disk".equals(d.getCode()))
                .map(d -> d.getValue().toString())
                .findFirst();
        Optional<String> npl = extendAttrDTOs.stream()
                .filter(d -> "npl".equals(d.getCode()))
                .map(d -> d.getValue().toString())
                .findFirst();
        Optional<String> hmodtyp = extendAttrDTOs.stream()
                .filter(d -> "hmodtyp".equals(d.getCode()))
                .map(d -> d.getValue().toString())
                .findFirst();
        if (!disk.isPresent() || !npl.isPresent() || !hmodtyp.isPresent()) {
            return Collections.emptySet();
        }
        return hondaGroupDAO.getNplblkByVin(npl.get(), hmodtyp.get(), disk.get());
    }

    @Override
    public List<SEPCPartsDTO> queryPartsByVinCodeAndLastGroup(SEPCPartsQueryParam param) {
        SEPCGroupDTO groupDTO = param.getGroupDTO();
        SEPCCarTypeDTO superCarTypeDTO = param.getSuperCarTypeDTO();
        if (Objects.isNull(groupDTO) || Objects.isNull(superCarTypeDTO) || CollectionUtils.isEmpty(superCarTypeDTO.getExtendAttrDTOs())) {
            return Collections.emptyList();
        }
        List<EPCPartsImageDTO> epcPartsImageDTOList = groupDTO.getEpcPartsImageDTOList();
        Optional<String> npl = superCarTypeDTO.getExtendAttrDTOs().stream()
                .filter(d -> "npl".equals(d.getCode()))
                .map(d -> d.getValue().toString())
                .findFirst();
        Optional<String> disk = superCarTypeDTO.getExtendAttrDTOs().stream()
                .filter(d -> "disk".equals(d.getCode()))
                .map(d -> d.getValue().toString())
                .findFirst();
        if (CollectionUtils.isEmpty(epcPartsImageDTOList) || !npl.isPresent() || !disk.isPresent()) {
            return Collections.emptyList();
        }
        String imageCode = epcPartsImageDTOList.get(0).getImageCode();
        List<SEPCHondaPartsInfoDTO> sepcHondaPartsInfoDTOS = sepcHondaPartsDAO.querySEPCPartsInfo(imageCode, npl.get(), disk.get());
        if (CollectionUtils.isEmpty(sepcHondaPartsInfoDTOS)) {
            return Collections.emptyList();
        }
        //填充配件图片及说明
        setPartsDesAndImage(sepcHondaPartsInfoDTOS, groupDTO, superCarTypeDTO, param.getLang());
        //填充btr主名
        setBtrPartsName(sepcHondaPartsInfoDTOS);

        //根据解析器规则进行过滤
        sepcHondaPartsInfoDTOS = filterByCarType(sepcHondaPartsInfoDTOS, superCarTypeDTO);

        //通过颜色进行过滤或设置颜色
        filterOrSetByVinColor(sepcHondaPartsInfoDTOS, superCarTypeDTO);

        List<SEPCPartsDTO> sepcPartsDTOS = Lists2.transformNonNull(sepcHondaPartsInfoDTOS, SEPCPartsTransformer.PARTS_INFO_TO_SEPC_PARTS_INFO);
        addFilterPoint(sepcPartsDTOS, epcPartsImageDTOList);
        return sepcPartsDTOS;
    }

    private void addFilterPoint(List<SEPCPartsDTO> sepcPartsDTOS, List<EPCPartsImageDTO> epcPartsImageDTOList) {
        EPCPartsImageDTO epcPartsImageDTO = epcPartsImageDTOList.get(0);
        List<EPCPartsImagePositionDTO> epcPartsImagePositionDTOs = epcPartsImageDTO.getEpcPartsImagePositionDTOs();
        if (CollectionUtils.isEmpty(epcPartsImagePositionDTOs)) {
            return;
        }
        List<String> point = sepcPartsDTOS.stream().map(SEPCPartsDTO::getCallout).collect(Collectors.toList());
        epcPartsImagePositionDTOs.removeIf(d -> point.contains(d.getPosition()));
        Map<String, List<EPCPartsImagePositionDTO>> pointMapping = epcPartsImagePositionDTOs.stream()
                .collect(Collectors.groupingBy(EPCPartsImagePositionDTO::getPosition));
        List<SEPCPartsDTO> filterPoint = pointMapping.keySet().stream().map(d -> {
            EPCPartsImageDTO imageDTO = new EPCPartsImageDTO();
            imageDTO.setImageCode(epcPartsImageDTO.getImageCode());
            imageDTO.setImageUrl(epcPartsImageDTO.getImageUrl());
            imageDTO.setImageName(epcPartsImageDTO.getImageName());
            imageDTO.setEpcPartsImagePositionDTOs(pointMapping.get(d));
            return SEPCPartsDTO.builder().epcPartsImageDTOs(Lists.newArrayList(imageDTO)).build();
        }).collect(Collectors.toList());
        sepcPartsDTOS.addAll(filterPoint);
    }

    private List<SEPCHondaPartsInfoDTO> filterByCarType(List<SEPCHondaPartsInfoDTO> sepcHondaPartsInfoDTOS, SEPCCarTypeDTO superCarTypeDTO) {
        if (CollectionUtils.isEmpty(sepcHondaPartsInfoDTOS) || Objects.isNull(superCarTypeDTO) || CollectionUtils.isEmpty(superCarTypeDTO.getExtendAttrDTOs())) {
            return Collections.emptyList();
        }
        HondaVinInfoDTO hondaVinInfoDTO = hondaEPCAnalyser.analyseVinCode(superCarTypeDTO.getVinCode());
        List<String> partsCodes = Lists2.transformNonNull(sepcHondaPartsInfoDTOS, SEPCHondaPartsInfoDTO::getNpartgenu);
        List<HondaPartsInfoDTO> partsInfos = StreamKit.partitionStream(partsCodes, SEGMENT_QUERY_SIZE)
                .flatMap(l -> hondaPartDAO.findPartsInfo(l, hondaVinInfoDTO.getNpl(), hondaVinInfoDTO.getDisk(), hondaVinInfoDTO.getNplblks()).stream())
                .collect(Collectors.toList());
        List<HondaPartsInfoDTO> partsInfoByFilter = hondaEPCAnalyser.filterPartsInfoByVinAnalyseResult(partsInfos, hondaVinInfoDTO);
        Map<String, List<HondaPartsInfoDTO>> partsCode2PartsInfo = partsInfoByFilter.stream().collect(Collectors.groupingBy(HondaPartsInfoDTO::getNpartgenu));

        return sepcHondaPartsInfoDTOS.stream()
                .filter(d -> filterByAnanlyserParts(d, partsCode2PartsInfo))
                .distinct()
                .collect(Collectors.toList());
    }

    private boolean filterByAnanlyserParts(SEPCHondaPartsInfoDTO partsInfoDTO, Map<String, List<HondaPartsInfoDTO>> partsCode2PartsInfo) {
        List<HondaPartsInfoDTO> hondaPartsInfoDTOS = partsCode2PartsInfo.get(partsInfoDTO.getNpartgenu());
        if (CollectionUtils.isEmpty(hondaPartsInfoDTOS)) {
            return false;
        }
        return hondaPartsInfoDTOS.stream().anyMatch(d -> d.getNplblk().equals(partsInfoDTO.getNplblk()) && d.getXordergun().equals(partsInfoDTO.getXordergun()));
    }

    private void setBtrPartsName(List<SEPCHondaPartsInfoDTO> sepcHondaPartsInfoDTOS) {
        if (CollectionUtils.isEmpty(sepcHondaPartsInfoDTOS)) {
            return;
        }
        Set<String> partsCodeSet = sepcHondaPartsInfoDTOS.stream()
                .map(SEPCHondaPartsInfoDTO::getNpartgenu)
                .collect(Collectors.toSet());
        List<HondaPartsMappingDTO> byPartsCode = partsMappingDAO.getByPartsCode(partsCodeSet);
        Map<String, String> partsCode2BtrPartsName = byPartsCode.stream()
                .collect(Collectors.toMap(HondaPartsMappingDTO::getPartsCode,
                        HondaPartsMappingDTO::getBtrPartsName,
                        (v1, v2) -> StringUtils.join(v1, ",", v2)));
        sepcHondaPartsInfoDTOS.forEach(d -> d.setBtrPartsName(partsCode2BtrPartsName.getOrDefault(d.getNpartgenu(), "")));
    }

    private void filterOrSetByVinColor(List<SEPCHondaPartsInfoDTO> sepcHondaPartsInfoDTOS, SEPCCarTypeDTO superCarTypeDTO) {
        if (CollectionUtils.isEmpty(sepcHondaPartsInfoDTOS)
                || Objects.isNull(superCarTypeDTO)
                || CollectionUtils.isEmpty(superCarTypeDTO.getExtendAttrDTOs())) {
            return;
        }
        Optional<String> npl = superCarTypeDTO.getExtendAttrDTOs().stream()
                .filter(d -> "npl".equals(d.getCode()))
                .map(d -> d.getValue().toString())
                .findFirst();
        Optional<String> disk = superCarTypeDTO.getExtendAttrDTOs().stream()
                .filter(d -> "disk".equals(d.getCode()))
                .map(d -> d.getValue().toString())
                .findFirst();
        if (!npl.isPresent() || !disk.isPresent()) {
            return;
        }
        Set<String> partsCodeSet = sepcHondaPartsInfoDTOS.stream().map(SEPCHondaPartsInfoDTO::getNpartgenu).collect(Collectors.toSet());
        List<SEPCHondaPartsColorDTO> sepcHondaPartsColorDTOS = sepcHondaPartsDAO.querySEPCPartsColor(partsCodeSet, npl.get(), disk.get());
        setPartsColor(sepcHondaPartsColorDTOS, sepcHondaPartsInfoDTOS);
        if (StringUtils.isBlank(superCarTypeDTO.getBodyColorExt()) || StringUtils.isBlank(superCarTypeDTO.getBodyColorInner())) {
            return;
        }
        String ext = superCarTypeDTO.getBodyColorExt();
        String inner = superCarTypeDTO.getBodyColorInner();
        Set<SEPCHondaPartsColorDTO> needFilter = sepcHondaPartsColorDTOS.stream()
                .filter(d -> !ext.equals(d.getChescolExt()))
                .filter(d -> !inner.equals(d.getCintecoltyp()))
                .collect(Collectors.toSet());
        Set<String> filterPartsCode = needFilter.stream().map(SEPCHondaPartsColorDTO::getNpartgenu).collect(Collectors.toSet());
        sepcHondaPartsInfoDTOS.removeIf(d -> filterPartsCode.contains(d.getNpartgenu()));
    }

    private void setPartsColor(List<SEPCHondaPartsColorDTO> sepcHondaPartsColorDTOS, List<SEPCHondaPartsInfoDTO> sepcHondaPartsInfoDTOS) {
        if (CollectionUtils.isEmpty(sepcHondaPartsColorDTOS)) {
            return;
        }
        Set<String> extSet = sepcHondaPartsColorDTOS.stream()
                .map(SEPCHondaPartsColorDTO::getChescolExt)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toSet());
        Set<String> innerSet = sepcHondaPartsColorDTOS.stream()
                .map(SEPCHondaPartsColorDTO::getCintecoltyp)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toSet());
        sepcHondaPartsInfoDTOS.forEach(d -> {
            d.setExtColor(extSet);
            d.setInnerColorType(innerSet);
        });
    }


    private void setPartsDesAndImage(List<SEPCHondaPartsInfoDTO> sepcHondaPartsInfoDTOS, SEPCGroupDTO groupDTO, SEPCCarTypeDTO superCarTypeDTO, String lang) {
        if (Objects.isNull(groupDTO) || Objects.isNull(superCarTypeDTO) || CollectionUtils.isEmpty(superCarTypeDTO.getExtendAttrDTOs())) {
            return;
        }
        Optional<String> disk = superCarTypeDTO.getExtendAttrDTOs().stream()
                .filter(d -> "disk".equals(d.getCode()))
                .map(d -> d.getValue().toString())
                .findFirst();
        if (!disk.isPresent()) {
            return;
        }
        setPartsDes(sepcHondaPartsInfoDTOS, disk.get(), lang);
        List<EPCPartsImageDTO> epcPartsImageDTOList = groupDTO.getEpcPartsImageDTOList();
        if (CollectionUtils.isEmpty(epcPartsImageDTOList) || CollectionUtils.isEmpty(epcPartsImageDTOList.get(0).getEpcPartsImagePositionDTOs())) {
            epcPartsImageDTOList = getSubEPCGroupImage(groupDTO, superCarTypeDTO.getExtendAttrDTOs());
        }

        setImageInParts(epcPartsImageDTOList, sepcHondaPartsInfoDTOS);
    }

    private void setImageInParts(List<EPCPartsImageDTO> epcPartsImageDTOList, List<SEPCHondaPartsInfoDTO> sepcHondaPartsInfoDTOS) {
        if (CollectionUtils.isEmpty(epcPartsImageDTOList)) {
            return;
        }
        Map<String, List<EPCPartsImageDTO>> imageCode2Image = epcPartsImageDTOList.stream().collect(Collectors.groupingBy(EPCPartsImageDTO::getImageCode));
        sepcHondaPartsInfoDTOS.forEach(d -> {
            EPCPartsImageDTO imageDTO = new EPCPartsImageDTO();
            List<EPCPartsImageDTO> epcPartsImageDTOS = imageCode2Image.get(d.getNplblk());
            if (CollectionUtils.isEmpty(epcPartsImageDTOS)) {
                return;
            }
            EPCPartsImageDTO partsImageDTO = epcPartsImageDTOS.get(0);
            imageDTO.setImageCode(partsImageDTO.getImageCode());
            imageDTO.setImageName(partsImageDTO.getImageName());
            imageDTO.setImageUrl(partsImageDTO.getImageUrl());
            List<EPCPartsImagePositionDTO> epcPartsImagePositionDTOs = partsImageDTO.getEpcPartsImagePositionDTOs();
            if (CollectionUtils.isNotEmpty(epcPartsImagePositionDTOs)) {
                List<EPCPartsImagePositionDTO> filterByPosition = epcPartsImagePositionDTOs.stream().filter(position -> StringUtils.equals(position.getPosition(), d.getNplpartref())).collect(Collectors.toList());
                imageDTO.setEpcPartsImagePositionDTOs(filterByPosition);
            }
            d.setEpcPartsImageDTOs(Lists.newArrayList(imageDTO));
        });
    }

    private List<EPCPartsImageDTO> getSubEPCGroupImage(SEPCGroupDTO groupDTO, List<SEPCExtendAttributeDTO> extendAttrDTOs) {
        //获取vin的所有子组
        Set<String> subGroupCode = getSubGroupCodeForVin(extendAttrDTOs);
        if (!subGroupCode.contains(groupDTO.getSubGroupCode())) {
            return Collections.emptyList();
        }
        //获取子组
        List<SEPCHondaSubGroupDTO> subGroupCodeByMG = getSubGroupCodeByMG(extendAttrDTOs, subGroupCode, groupDTO);
        Optional<SEPCHondaSubGroupDTO> subGroupDTO = subGroupCodeByMG.stream()
                .filter(d -> StringUtils.equals(d.getNplblk(), groupDTO.getSubGroupCode()))
                .findFirst();
        if (!subGroupDTO.isPresent()) {
            return Collections.emptyList();
        }
        return subGroupDTO.get().getEpcPartsImageDTOList();
    }

    private void setPartsDes(List<SEPCHondaPartsInfoDTO> sepcHondaPartsInfoDTOS, String disk, String lang) {
        Set<String> partsCodeSet = sepcHondaPartsInfoDTOS.stream().map(SEPCHondaPartsInfoDTO::getNpartgenu).collect(Collectors.toSet());
        List<SEPCHondaPartsInfoDTO> partsDesList;
        if (LangEnum.EN.getLang().equals(lang)) {
            partsDesList = sepcHondaPartsDAO.querySEPCPartsDes(partsCodeSet, disk);
        } else {
            partsDesList = sepcHondaPartsDAO.querySEPCPartsDesForCN(partsCodeSet);
        }
        if (CollectionUtils.isNotEmpty(partsDesList)) {
            Map<String, String> partsCode2PartsDes = partsDesList.stream()
                    .collect(Collectors.toMap(SEPCHondaPartsInfoDTO::getNpartgenu, SEPCHondaPartsInfoDTO::getXpartext, (v1, v2) -> v1));
            sepcHondaPartsInfoDTOS.forEach(d -> {
                d.setXpartext(partsCode2PartsDes.get(d.getNpartgenu()));
            });
        }
    }

    @Override
    public List<SEPCSearchGroupDTO> queryGroupsByVinCodeAndParts(SEPCPartsQueryParam param) {
        SEPCPartsDTO partsDTO = param.getPartsDTO();
        SEPCCarTypeDTO superCarTypeDTO = param.getSuperCarTypeDTO();

        if (Objects.isNull(superCarTypeDTO) || CollectionUtils.isEmpty(superCarTypeDTO.getExtendAttrDTOs())) {
            return Collections.emptyList();
        }
        Optional<String> npl = superCarTypeDTO.getExtendAttrDTOs().stream()
                .filter(d -> "npl".equals(d.getCode()))
                .map(d -> d.getValue().toString())
                .findFirst();
        Optional<String> disk = superCarTypeDTO.getExtendAttrDTOs().stream()
                .filter(d -> "disk".equals(d.getCode()))
                .map(d -> d.getValue().toString())
                .findFirst();
        String partsCode = partsDTO.getPartsCode();
        if (StringUtils.isEmpty(partsCode) || !npl.isPresent() || !disk.isPresent()) {
            return Collections.emptyList();
        }
        List<SEPCHondaPartsInfoDTO> sepcHondaPartsInfoDTOS = sepcHondaPartsDAO.querySEPCPartsInfoByPartsCode(partsCode, npl.get(), disk.get());
        if (CollectionUtils.isEmpty(sepcHondaPartsInfoDTOS)) {
            return Collections.emptyList();
        }
        Set<String> subCodes = Sets2.transformNonNull(sepcHondaPartsInfoDTOS, SEPCHondaPartsInfoDTO::getNplblk);
        Set<String> sureSubGroupCode = getSubGroupCodeForVin(param.getSuperCarTypeDTO().getExtendAttrDTOs());
        subCodes.removeIf(d -> !sureSubGroupCode.contains(d));
        if (CollectionUtils.isEmpty(subCodes)) {
            return Collections.emptyList();
        }
        List<SEPCHondaSubGroupDTO> subGroupCodeList = hondaGroupDAO.querySubCodeByNplgrp(subCodes, npl.get(), disk.get());
        if (CollectionUtils.isEmpty(subGroupCodeList)) {
            return Collections.emptyList();
        }
        List<SEPCHondaSubGroupDTO> subGroupDesList = hondaGroupDAO.querySubDes(npl.get(), subCodes, disk.get());
        if (CollectionUtils.isEmpty(subGroupDesList)) {
            return Collections.emptyList();
        }
        setGroupDes(subGroupCodeList, subGroupDesList);

        List<SEPCGroupDTO> sepcGroupDTOS = Lists2.transformNonNull(subGroupCodeList, SEPCGroupTransformer.SUB_GROUP_TO_SEPC_SUB_GROUP);
        setParenGroupInSEPCGroup(subGroupCodeList, sepcGroupDTOS);
        return sepcGroupDTOS.stream()
                .map(d -> SEPCSearchGroupDTO.builder().groupDTO(d).partsDTO(partsDTO).build())
                .collect(Collectors.toList());
    }

    private void setParenGroupInSEPCGroup(List<SEPCHondaSubGroupDTO> subGroupCodeList, List<SEPCGroupDTO> sepcGroupDTOS) {
        Set<String> mainGroupCode = Sets2.transformNonNull(subGroupCodeList, SEPCHondaSubGroupDTO::getNplgrp);
        List<SEPCGroupDTO> mainGroupList = hondaGroupDAO.queryMainGroupByCodes(mainGroupCode);
        if (CollectionUtils.isEmpty(mainGroupList)) {
            return;
        }
        Map<String, SEPCGroupDTO> mainCode2GroupList = mainGroupList.stream().collect(Collectors.toMap(SEPCGroupDTO::getMainGroupCode, d -> d, (v1, v2) -> v1));
        sepcGroupDTOS.forEach(d -> d.setParentGroup(mainCode2GroupList.get(d.getMainGroupCode())));

    }

    @Override
    public List<SEPCSearchPartsDTO> queryPartsByVinCodeAndParts(SEPCPartsQueryParam param) {
        SEPCPartsDTO partsDTO = param.getPartsDTO();
        SEPCCarTypeDTO superCarTypeDTO = param.getSuperCarTypeDTO();

        if (Objects.isNull(superCarTypeDTO) || CollectionUtils.isEmpty(superCarTypeDTO.getExtendAttrDTOs())) {
            return Collections.emptyList();
        }
        Optional<String> npl = superCarTypeDTO.getExtendAttrDTOs().stream()
                .filter(d -> "npl".equals(d.getCode()))
                .map(d -> d.getValue().toString())
                .findFirst();
        Optional<String> disk = superCarTypeDTO.getExtendAttrDTOs().stream()
                .filter(d -> "disk".equals(d.getCode()))
                .map(d -> d.getValue().toString())
                .findFirst();
        String partsCode = partsDTO.getPartsCode();
        if (StringUtils.isEmpty(partsCode) || !npl.isPresent() || !disk.isPresent()) {
            return Collections.emptyList();
        }
        List<SEPCHondaPartsInfoDTO> sepcHondaPartsInfoDTOS = Lists.newArrayList(SEPCHondaPartsInfoDTO.builder()
                .npartgenu(partsDTO.getPartsCode())
                .build());

        setPartsDes(sepcHondaPartsInfoDTOS, disk.get(), param.getLang());
        List<SEPCPartsDTO> sepcPartsDTOS = Lists2.transformNonNull(sepcHondaPartsInfoDTOS, SEPCPartsTransformer.PARTS_INFO_TO_SEPC_PARTS_INFO);
        return sepcPartsDTOS.stream().map(d -> SEPCSearchPartsDTO.builder().partsDTO(d).build()).collect(Collectors.toList());
    }
}
